home *** CD-ROM | disk | FTP | other *** search
- /************************************************************
-
- AScriptParse.c
- C Source to Preditor 3
-
- Language Module Code for the "AppleScript" language
-
- © Copyright Evatac Software 1988-1996
- All rights reserved
-
- ************************************************************/
-
- #include "AScriptParse.h"
- #include <SetupA4.h>
- #include <MixedMode.h>
- #include <Ctype.h>
-
- #ifndef THINKC
- #include <A4Stuff.h>
- #else
- #define SetCurrentA4() 0; RememberA4()
- #define SetA4(x) SetUpA4()
- #endif
-
- #ifdef powerc
- ProcInfoType __procinfo = LanguageUPPInfo;
- #endif
-
- static languageGlobals globals;
- static ExternalCallbackBlock *callbacks;
-
-
- /*
- * * * * APPLESCRIPT LANGUAGE INDENT HANDLER * * * * * *
- */
-
- static long _languageConvertToTabs(
- Char *text,
- long length,
- long hardTab
- )
- {
- int tabs = length / hardTab;
- int spaces = length % hardTab;
- int newLen = tabs + spaces;
-
- while (tabs-- > 0)
- *(text++) = 9;
- while (spaces-- > 0)
- *(text++) = ' ';
-
- return(newLen);
- }
-
- /*
- * _languageHandleIndent
- *
- * Indent the selected lines according to the buffer indentation settings
- */
- static void _languageHandleIndent(
- void *extData
- )
- {
- long anchor, end, pos, length;
- long lineStart;
- long i, x, newPos = -1;
- long lineNumber, endLineNumber, leading;
- short spacesPerTab, hardTab;
- Char text[256];
-
- extGetSelection(callbacks, &anchor, &end);
-
- if (anchor > end) {
- pos = anchor; anchor = end; end = pos; /* Swap */
- }
-
- lineNumber = extLineFromPosition(callbacks, anchor);
- endLineNumber = extLineFromPosition(callbacks, end);
-
- /*
- * Indent each line in the selection
- */
-
- while (lineNumber <= endLineNumber) {
-
- if (lineNumber <= 1) {
- lineNumber++;
- continue;
- }
-
- leading = extGetLeading(callbacks, lineNumber, &length,
- &spacesPerTab, &hardTab);
-
- lineStart = extLineToPosition(callbacks, lineNumber);
-
- /*
- * Select the leading spaces/tabs
- */
-
- extSetSelection(callbacks, lineStart, lineStart + length);
-
- /*
- * Scan back previous lines for a line that we can relate to
- */
-
- x = 1;
-
- for (;;) {
-
- if (lineNumber - x < 1)
- break;
-
- leading = extGetLeading(callbacks, lineNumber - x, &length,
- &spacesPerTab, &hardTab);
-
- end = extLineEnd(callbacks, lineNumber - x);
- pos = extLineToPosition(callbacks, lineNumber - x);
-
- /* Skip Blank lines */
-
- if (length == (end - pos)) {
- x++;
- continue;
- }
-
- i = pos + length;
-
- /*
- * Perform Indention Smarts (Still under development)
- */
-
- extScanContents(callbacks, i);
-
- /* while (i++ < end && extNextScanCharacter(callbacks, &ch)) {
-
- if (ch == '{') {
- leading += spacesPerTab;
- break;
- }
- } */
-
- extDoneScan(callbacks);
-
-
- /*
- * Indent the line
- */
-
- i = _languageConvertToTabs(text, leading, hardTab);
-
- extInsert(callbacks, text, i);
-
- if (newPos == -1)
- newPos = lineStart + i;
- break;
- }
-
- lineNumber++;
- }
-
- if (newPos >= 0)
- extSetSelection(callbacks, newPos, newPos);
- }
-
- /*
- * * * * APPLESCRIPT LANGUAGE PARSER * * * * * *
- */
-
- /*
- * _languageBuildString
- *
- * Build up a literal string or literal contant "foo" or 'foo'
- */
- static void _languageBuildString(
- languageToken *token,
- int c
- )
- {
- Int32 index = 1, size = kTokenStringSize;
- int origC = c;
-
- token->string[1] = c;
- token->type = (c == '\"' ? kSymbolStringLiteral : kSymbolCharConstant);
-
- if (c == 'l' || c == 'L') {
-
- c = languageGetChar(&globals, callbacks);
- token->string[0] = c;
- index = 2;
- }
-
- while ((c = languageGetChar(&globals, callbacks)) != -1) {
-
- if (index < size)
- token->string[++index] = c;
-
- if (c == origC)
- break;
-
- else if (c == '\\') {
-
- c = languageGetChar(&globals, callbacks);
-
- if (c != -1) {
-
- if (index < size)
- token->string[++index] = c;
- }
- }
- }
-
- token->string[0] = index; /* So string can be used as C or Pascal string */
- token->string[++index] = 0;
- }
-
- /*
- * _languageBuildWhiteSpace
- *
- * Build up a directive (i.e. #define, etc)
- */
- static void _languageBuildWhiteSpace(
- languageToken *token,
- int c
- )
- {
- token->type = kSymbolWhiteSpace;
-
- while ((c = languageGetChar(&globals, callbacks)) != -1) {
-
- if (c != ' ' && c != '\t' && c != '\v' && c != '\n' &&
- c != '\r' && c != '\f' && c != '\b') {
- // if (!isspace(c)) {
- languageUngetChar(&globals, c);
- return;
- }
- }
- }
-
- /*
- * _languageBuildComment
- *
- */
- static void _languageBuildComment(
- languageToken *token,
- int c
- )
- {
- token->type = kSymbolComment;
- globals.startLastComment = globals.position;
-
- while ((c = languageGetChar(&globals, callbacks)) != -1) {
-
- if (c == 13)
- break;
- }
- }
-
- /*
- * _languageBuildNumber
- *
- */
- static void _languageBuildNumber(
- languageToken *token,
- int c
- )
- {
- token->type = kSymbolIntConstant;
-
- if (c == '0') {
-
- c = languageGetChar(&globals, callbacks);
-
- if (c == 'x' || c == 'X') {
-
- while ((c = languageGetChar(&globals, callbacks)) != -1) {
-
- if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))
- ;
- else
- break;
- }
- }
-
- else {
-
- while (c != -1) {
-
- if (c >= '0' && c <= '7')
- ;
- else
- break;
-
- c = languageGetChar(&globals, callbacks);
- }
- }
- }
-
- else { /* decimal */
-
- while ((c = languageGetChar(&globals, callbacks)) != -1) {
-
- if (c >= '0' && c <= '9')
- ;
- else
- break;
- }
-
- if (c == '.') {
-
- token->type = kSymbolFloatConstant;
-
- while ((c = languageGetChar(&globals, callbacks)) != -1) {
-
- if (c >= '0' && c <= '9')
- ;
- else
- break;
- }
- }
-
- if (c == 'e' || c == 'E') {
-
- token->type = kSymbolFloatConstant;
-
- c = languageGetChar(&globals, callbacks);
-
- if (c == '-' || c == '+')
- c = languageGetChar(&globals, callbacks);
-
- while (c != -1) {
-
- if (c >= '0' && c <= '9')
- ;
- else
- break;
-
- c = languageGetChar(&globals, callbacks);
- }
- }
- }
-
- while (c != -1) {
-
- if (c == 'l' || c == 'L' || c == 'u' || c == 'U' ||
- c == 'f' || c == 'F' || c == 'h' || c == 'H')
- ;
- else
- break;
-
- c = languageGetChar(&globals, callbacks);
- }
-
- if (c != -1)
- languageUngetChar(&globals, c);
- }
-
- /*
- * _languageBuildWord
- *
- *
- */
- static void _languageBuildWord(
- languageToken *token,
- int c
- )
- {
- Int32 index = 1, size = kTokenStringSize;
- Char *scan;
-
- token->type = kSymbolIdentifier;
-
- token->string[1] = c;
-
- while ((c = languageGetChar(&globals, callbacks)) != -1) {
-
- if (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c == '_'
- || c >= '0' && c <= '9') {
-
- if (index < size)
- token->string[++index] = c;
- }
- else {
-
- languageUngetChar(&globals, c);
- break;
- }
- }
-
- token->string[0] = index; /* So string can be used as C or Pascal string */
- token->string[++index] = 0;
-
- if (!languageHasTable(&globals)) {
-
- scan = token->string + 1;
-
- if (languageCStringCompare(scan, (Char *) "on") == 0)
- token->type = kSymbolReservedWord;
-
- return;
- }
-
- else if (languageTableLookup((&globals), token->string + 1))
- token->type = kSymbolReservedWord;
- else if (languageCustomTableLookup((&globals), token->string + 1))
- token->type = kSymbolCustomWord;
- }
-
- /*
- * _languageGetNextToken
- */
- static languageToken *_languageGetNextToken(void)
- {
- int first, second;
- Int16 previousType;
- languageToken *token = &globals.token;
-
- previousType = token->type;
- token->startLocation = globals.position;
- token->majorType = -1;
-
- if ((first = languageGetChar(&globals, callbacks)) == -1)
- return(nil);
-
- token->type = first;
-
- second = languagePeekChar(&globals, callbacks);
-
- switch(first) {
-
- /* "strings" */
- /* 'character constants' */
-
- case '\"':
- case '\'':
- _languageBuildString(token, first);
- break;
-
- /* white space */
-
- case ' ': case '\t': case '\v': case '\n': case '\r': case '\f': case '\b':
- _languageBuildWhiteSpace(token, first);
- break;
-
- /* monographs */
- case ';':
- globals.startLastComment = -1;
- case '(':
- case '#':
- case ')':
- case '[':
- case ']':
- case '}':
- case '~':
- case '\\':
- case ',':
- case '?':
- case '/':
- break;
-
- /* *, *= */
-
- case '*':
- if (second == '=') {
- languageGetChar(&globals, callbacks);
- token->type = kSymbolMultiplyAssign;
- }
- break;
-
- /* %, %= */
-
- case '%':
- if (second == '=') {
- languageGetChar(&globals, callbacks);
- token->type = kSymbolModAssign;
- }
- break;
-
- /* !, != */
-
- case '!':
- if (second == '=') {
- languageGetChar(&globals, callbacks);
- token->type = kSymbolNotEqual;
- }
- break;
-
- /* &, &=, && */
-
- case '&':
- if (second == '=') {
- languageGetChar(&globals, callbacks);
- token->type = kSymbolAndAssign;
- }
- else if (second == '&') {
- languageGetChar(&globals, callbacks);
- token->type = kSymbolAndAnd;
- }
- break;
-
- /* |, ||, |= */
-
- case '|':
- if (second == '=') {
- languageGetChar(&globals, callbacks);
- token->type = kSymbolOrAssign;
- }
- else if (second == '|') {
- languageGetChar(&globals, callbacks);
- token->type = kSymbolOrOr;
- }
- break;
-
- /* +, ++, += */
-
- case '+':
- if (second == '=') {
- languageGetChar(&globals, callbacks);
- token->type = kSymbolPlusAssign;
- }
- break;
-
- /* -, --, -=, ->, ->* */
-
- case '-':
- if (second == '-') { /* Comment */
- _languageBuildComment(token, first);
- }
- else if (second == '=') {
- languageGetChar(&globals, callbacks);
- token->type = kSymbolMinusAssign;
- }
- else if (second == '>') {
- languageGetChar(&globals, callbacks);
- second = languagePeekChar(&globals, callbacks);
-
- if (second == '*') {
- languageGetChar(&globals, callbacks);
- token->type = kSymbolPointerStar;
- }
- else
- token->type = kSymbolPointer;
- }
- break;
-
- /* ., .*, .NUM */
-
- case '.':
- if (second == '*') {
- languageGetChar(&globals, callbacks);
- token->type = kSymbolDotStar;
- }
-
- else if (second >= '0' && second <= '9')
- _languageBuildNumber(token, first);
-
- else if (second == '.') {
-
- languageGetChar(&globals, callbacks);
-
- if (languagePeekChar(&globals, callbacks) == '.') {
- languageGetChar(&globals, callbacks);
- token->type = kSymbolEllipsis;
- }
- else {
- languageUngetChar(&globals, second);
- }
- }
- break;
-
- /* =, == */
-
- case '=':
- if (second == '=') {
- languageGetChar(&globals, callbacks);
- token->type = kSymbolEqual;
- }
- break;
-
- /* <, <<, <=, <<= */
-
- case '<':
- if (second == '=') {
- languageGetChar(&globals, callbacks);
- token->type = kSymbolLessOrEqual;
- }
- else if (second == '>') {
- languageGetChar(&globals, callbacks);
- token->type = kSymbolNotEqual;
- }
- break;
-
- /* >, >=, >>, >>= */
-
- case '>':
- if (second == '=') {
- languageGetChar(&globals, callbacks);
- token->type = kSymbolGreaterOrEqual;
- }
- break;
-
- /* ^, ^= */
-
- case '^':
- if (second == '=') {
- languageGetChar(&globals, callbacks);
- token->type = kSymbolXOrAssign;
- }
- break;
-
- /* :, := */
-
- case ':':
- if (second == ':') {
- languageGetChar(&globals, callbacks);
- token->type = kSymbolAssign;
- }
- break;
-
- /* the rest */
-
- default:
- if (first >= '0' && first <= '9')
- _languageBuildNumber(token, first);
- else if (first >= 'a' && first <= 'z' || first >= 'A' && first <= 'Z' ||
- first == '_')
- _languageBuildWord(token, first);
-
- /* Something weird, let the parser decide. */
-
- break;
- }
-
- token->endLocation = globals.position;
-
- return(token);
- }
-
- void languageMain(
- ExternalCallbackBlock *extCallbacks,
- WindowRef window,
- long options,
- void *extData
- );
-
- /*
- * languageMain
- *
- * This is the main entrypoint to the CODE module of a language module.
- * The following operations are defined:
- *
- * kLanguageParse Parse the source file, returning positions of all tokens
- * in the file.
- * kLanguageFunctions Parse the source file, returning the position of just the
- * functions in the source file
- * kLanguageIncludes Parse the source file, returning the #include files
- * kLanguageTemplate Expand macro -- insert template
- * kLanguageIndentLine
- * kLanguageElectric Handle electric characters (i.e. }, {, ; )
- */
-
- void main(
- ExternalCallbackBlock *extCallbacks,
- WindowRef window,
- long options,
- void *extData
- )
- {
- languageToken *token;
- Int16 type;
- Char *ptr;
- long saved_a4;
-
- saved_a4 = SetCurrentA4();
-
- languageInit(&globals, extCallbacks, options);
-
- callbacks = extCallbacks;
-
- if (options == kLanguageTemplate) {
-
- languageDefaultHandler(&globals, callbacks, options, extData);
- }
-
- else if (options == kLanguageIndent) {
-
- _languageHandleIndent(extData);
- }
-
- else if (options <= kLanguageIncludes) {
-
- /*
- * Now parse the file, returning a series of valid return token types:
- *
- * kFunction
- * kKeyword
- * kComment
- * kCustomKeyword
- */
-
- while ((token = _languageGetNextToken()) != nil) {
-
- type = token->type;
-
- if (type == kSymbolReservedWord) {
-
- token->majorType = kKeyword;
- ptr = token->string;
-
- if (options == kLanguageParse)
- extTokenReturn(callbacks, token);
-
- if (ptr[1] == 'o' && options != kLanguageIncludes) { /* on */
-
- while ((token = _languageGetNextToken()) != nil) {
- if (token->type != kSymbolWhiteSpace)
- break;
- }
-
- if (token->type != kSymbolReservedWord) {
- token->majorType = kFunction;
- token->commentLocation = -1;
- extTokenReturn(callbacks, token);
- }
- else
- token->majorType = kKeyword;
- }
-
- }
-
- else if (type == kSymbolCustomWord) {
- token->majorType = kCustomKeyword;
- }
-
- else if (type == kSymbolComment)
- token->majorType = kComment;
-
- /*
- * Only return a token if it's a interesting token, and
- * if we are doing a full parse
- */
-
- if (token->majorType >= 0 && options == kLanguageParse)
- extTokenReturn(callbacks, token);
- }
- }
-
- /*
- * Clean up after ourselves
- */
-
- languageDone(&globals, callbacks);
-
- SetA4(saved_a4);
- }
-